from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _


class Subject(models.Model):
    """科目模型"""
    name = models.CharField(max_length=50, unique=True, verbose_name="科目名称")
    full_score = models.FloatField(default=150, verbose_name="满分", validators=[MinValueValidator(0)])
    color = models.CharField(max_length=7, default="#3498db", verbose_name="显示颜色")
    order = models.IntegerField(default=0, verbose_name="显示顺序", validators=[MinValueValidator(0)])

    class Meta:
        verbose_name = "科目"
        verbose_name_plural = "科目信息"
        ordering = ['order']

    def __str__(self):
        return self.name


class ExamType(models.Model):
    """考试类型模型"""
    name = models.CharField(max_length=50, verbose_name="考试类型")
    description = models.TextField(blank=True, verbose_name="类型描述")

    class Meta:
        verbose_name = "考试类型"
        verbose_name_plural = "考试类型"

    def __str__(self):
        return self.name


class Exam(models.Model):
    """考试模型"""
    name = models.CharField(max_length=100, verbose_name="考试完整名称")  # 暂时保留
    base_name = models.CharField(max_length=100, verbose_name="考试基础名称", blank=True, null=True)  # 如"历年真题"
    sequence_number = models.IntegerField(verbose_name="序号", blank=True, null=True)  # 如2006
    exam_type = models.ForeignKey(ExamType, on_delete=models.SET_NULL, null=True, verbose_name="考试类型")
    exam_date = models.DateField(verbose_name="考试日期")
    description = models.TextField(blank=True, verbose_name="考试说明")
    total_score = models.FloatField(default=150, verbose_name="总分", validators=[MinValueValidator(0)])
    difficulty_level = models.FloatField(verbose_name="试卷难度",
                                        validators=[MinValueValidator(0), MaxValueValidator(10)])

    class Meta:
        verbose_name = "考试"
        verbose_name_plural = "考试信息"
        ordering = ['-exam_date']
        # 先注释掉 unique_together，等数据迁移完成后再启用
        # unique_together = ['base_name', 'sequence_number']

    def __str__(self):
        # 如果 base_name 和 sequence_number 有值，使用新格式，否则使用旧名称
        if self.base_name and self.sequence_number is not None:
            return f"{self.base_name}-{self.sequence_number} ({self.exam_date})"
        else:
            return f"{self.name} ({self.exam_date})"

    @property
    def full_name(self):
        """返回完整的考试名称：基础名称-序号"""
        if self.base_name and self.sequence_number is not None:
            return f"{self.base_name}-{self.sequence_number}"
        else:
            return self.name

    def clean(self):
        """验证序号不能为负数"""
        if self.sequence_number and self.sequence_number < 0:
            raise ValidationError(_('序号不能为负数'))


class ExamRecord(models.Model):
    """考试成绩记录模型"""

    # 考试状态选择
    EXAM_STATUS_CHOICES = [
        ('excellent', '状态极佳'),
        ('good', '状态良好'),
        ('normal', '状态一般'),
        ('poor', '状态不佳'),
        ('sick', '带病考试')
    ]

    # 时间管理选择
    TIME_MANAGEMENT_CHOICES = [
        ('excellent', '时间充足'),
        ('good', '时间刚好'),
        ('tight', '时间紧张'),
        ('insufficient', '时间不足')
    ]

    # 基础字段
    student = models.ForeignKey('users.Student', on_delete=models.CASCADE, related_name="exam_records")
    exam = models.ForeignKey(Exam, on_delete=models.CASCADE, related_name="records")
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE, related_name="records")

    # 成绩相关字段
    score = models.FloatField(verbose_name="得分", validators=[MinValueValidator(0)])
    target_score = models.FloatField(
        verbose_name="理想分数",
        null=True,
        blank=True,
        validators=[MinValueValidator(0)],
        help_text="期望达到的分数"
    )

    # 考试详情字段
    exam_duration = models.IntegerField(null=True, blank=True, verbose_name="考试用时(分钟)")
    question_completion = models.FloatField(
        verbose_name="题目完成度",
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(100)],
        help_text="0-100%"
    )
    difficulty_level = models.FloatField(
        verbose_name="难度系数",
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(10)],
        help_text="0-10之间，数字越大难度越高"
    )

    # 状态管理字段
    exam_status = models.CharField(
        max_length=20,
        verbose_name="考试状态",
        blank=True,
        choices=EXAM_STATUS_CHOICES
    )
    time_management = models.CharField(
        max_length=20,
        verbose_name="时间管理",
        blank=True,
        choices=TIME_MANAGEMENT_CHOICES
    )

    # 时间戳
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="记录时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "考试成绩"
        verbose_name_plural = "考试成绩记录"
        unique_together = ['student', 'exam', 'subject']
        ordering = ['-exam__exam_date', 'subject__order']

    def __str__(self):
        return f"{self.student.name} - {self.exam.full_name} - {self.subject.name}: {self.score}"

    @property
    def loss_points(self):
        """计算失分"""
        return self.subject.full_score - self.score

    def clean(self):
        """模型级验证"""
        # 验证理想分数不超过科目满分
        if self.target_score and self.target_score > self.subject.full_score:
            raise ValidationError(f'理想分数不能超过科目满分({self.subject.full_score}分)')

        # 验证实际分数不超过科目满分
        if self.score > self.subject.full_score:
            raise ValidationError(f'实际分数不能超过科目满分({self.subject.full_score}分)')

    def save(self, *args, **kwargs):
        """保存前进行验证"""
        self.clean()
        super().save(*args, **kwargs)


class KnowledgePoint(models.Model):
    """知识点模型"""
    subject = models.ForeignKey(Subject, on_delete=models.CASCADE, related_name="knowledge_points")
    name = models.CharField(max_length=100, verbose_name="知识点名称")
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True,
                               related_name="children", verbose_name="父级知识点")
    weight = models.FloatField(default=1.0, verbose_name="权重",validators=[MinValueValidator(0)],help_text="知识点在考试中的重要程度")
    order = models.IntegerField(default=0, verbose_name="显示顺序", validators=[MinValueValidator(0)])
    is_custom = models.BooleanField(default=False, verbose_name="是否为学生自定义")
    created_by = models.ForeignKey('users.Student', on_delete=models.SET_NULL,
                                   null=True, blank=True, verbose_name="创建者")

    class Meta:
        verbose_name = "知识点"
        verbose_name_plural = "知识点管理"
        ordering = ['subject', 'order']
        unique_together = ['subject', 'name']

    def __str__(self):
        return f"{self.subject.name} - {self.name}"

    def clean(self):
        # 确保自定义知识点的创建者不为空
        if self.is_custom and not self.created_by:
            raise ValidationError(_('自定义知识点必须指定创建者'))


class ScoreLossDetail(models.Model):
    """失分明细模型"""

    # 失分类型选择定义
    LOSS_TYPE_CHOICES = [
        # 计算相关错误
        ('calculation_error', '计算错误', {
            'description': '基本的算术运算错误，如加减乘除算错',
            'icon': '🧮',
            'color': '#ff6b6b'
        }),
        ('formula_error', '公式运用错误', {
            'description': '公式记错或用错条件',
            'icon': '∫',
            'color': '#ff9ff3'
        }),
        ('unit_error', '单位错误', {
            'description': '单位换算或忘记写单位',
            'icon': '📏',
            'color': '#feca57'
        }),

        # 知识掌握问题
        ('concept_not_understood', '概念不清', {
            'description': '对基本概念理解不透彻',
            'icon': '❓',
            'color': '#48dbfb'
        }),
        ('knowledge_gap', '知识点空白', {
            'description': '完全没学过这个知识点',
            'icon': '⬜',
            'color': '#dfe6e9'
        }),
        ('memory_lapse', '记忆模糊', {
            'description': '学过但忘记了，记忆不牢固',
            'icon': '💭',
            'color': '#a29bfe'
        }),

        # 理解与审题问题
        ('misunderstanding', '理解错误', {
            'description': '对题目要求理解有偏差',
            'icon': '🔍',
            'color': '#fd79a8'
        }),
        ('misreading', '审题失误', {
            'description': '看错数字、漏看条件等',
            'icon': '👓',
            'color': '#e17055'
        }),
        ('question_misinterpreted', '题意理解偏差', {
            'description': '完全理解错了题目意图',
            'icon': '🔄',
            'color': '#00b894'
        }),

        # 技能与方法问题
        ('method_error', '方法选择错误', {
            'description': '解题方法选择不当',
            'icon': '🛠️',
            'color': '#fdcb6e'
        }),
        ('process_error', '步骤错误', {
            'description': '解题步骤混乱或缺失',
            'icon': '📋',
            'color': '#74b9ff'
        }),
        ('skill_deficiency', '技巧不足', {
            'description': '缺乏特定的解题技巧',
            'icon': '🎯',
            'color': '#a29bfe'
        }),

        # 考试策略问题
        ('time_management', '时间不足', {
            'description': '做题速度慢，时间不够用',
            'icon': '⏰',
            'color': '#636e72'
        }),
        ('careless_mistake', '粗心大意', {
            'description': '非知识性失误，如抄错数字',
            'icon': '⚠️',
            'color': '#ff7675'
        }),
        ('answer_format', '答题规范问题', {
            'description': '格式不规范、未按要求答题',
            'icon': '📝',
            'color': '#00cec9'
        }),

        # 心理与状态问题
        ('nervous_error', '紧张失误', {
            'description': '考试紧张导致的错误',
            'icon': '😰',
            'color': '#6c5ce7'
        }),
        ('overthinking', '想得太复杂', {
            'description': '把简单问题复杂化',
            'icon': '🤯',
            'color': '#b2bec3'
        }),
        ('rushing', '急于求成', {
            'description': '为了赶时间而粗心',
            'icon': '💨',
            'color': '#f368e0'
        }),

        # 其他类型
        ('guess_wrong', '猜错答案', {
            'description': '蒙题但蒙错了',
            'icon': '🎲',
            'color': '#ffeaa7'
        }),
        ('omission', '漏做题', {
            'description': '完全忘记做某道题',
            'icon': '📄',
            'color': '#dfe6e9'
        }),
        ('other', '其他原因', {
            'description': '其他未分类的失分原因',
            'icon': '📌',
            'color': '#b2bec3'
        }),
    ]

    # 简化版的choices用于数据库字段
    LOSS_TYPE_SIMPLE_CHOICES = [
        (choice[0], choice[1]) for choice in LOSS_TYPE_CHOICES
    ]

    # 数据库字段
    exam_record = models.ForeignKey(ExamRecord, on_delete=models.CASCADE, related_name="loss_details")
    loss_type = models.CharField(
        max_length=50,
        choices=LOSS_TYPE_SIMPLE_CHOICES,
        verbose_name="失分类型"
    )
    knowledge_point = models.ForeignKey(
        KnowledgePoint,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name="涉及知识点"
    )
    custom_knowledge_point = models.CharField(
        max_length=100,
        blank=True,
        verbose_name="自定义知识点",
        help_text="如果现有知识点不适用，请在此输入新的知识点名称"
    )
    points = models.FloatField(
        validators=[MinValueValidator(0.5)],
        verbose_name="失分分值"
    )
    question_number = models.CharField(max_length=10, blank=True, verbose_name="题号")
    description = models.TextField(blank=True, verbose_name="详细描述")
    is_understand = models.BooleanField(default=False, verbose_name="是否已掌握")
    review_date = models.DateField(null=True, blank=True, verbose_name="复习日期")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    class Meta:
        verbose_name = "失分明细"
        verbose_name_plural = "失分明细记录"
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.get_loss_type_display()}: -{self.points}分"

    def clean(self):
        # 验证知识点和自定义知识点不能同时为空或同时有值
        if not self.knowledge_point and not self.custom_knowledge_point:
            raise ValidationError(_('必须选择知识点或输入自定义知识点'))

        if self.knowledge_point and self.custom_knowledge_point:
            raise ValidationError(_('不能同时选择知识点和输入自定义知识点'))

        # 验证失分分值不超过该题目的可能分值
        if hasattr(self, 'exam_record') and self.points > self.exam_record.subject.full_score:
            raise ValidationError(_('失分分值不能超过科目满分'))

    def save(self, *args, **kwargs):
        # 在保存前进行数据验证
        self.clean()

        # 如果有自定义知识点，创建新的知识点
        if self.custom_knowledge_point and not self.knowledge_point:
            # 获取科目
            subject = self.exam_record.subject

            # 创建新的知识点
            knowledge_point = KnowledgePoint.objects.create(
                subject=subject,
                name=self.custom_knowledge_point,
                is_custom=True,
                created_by=self.exam_record.student
            )
            self.knowledge_point = knowledge_point
            self.custom_knowledge_point = ""  # 清空自定义字段

        super().save(*args, **kwargs)

    # 获取失分类型的详细信息
    def get_loss_type_info(self):
        for choice in self.LOSS_TYPE_CHOICES:
            if choice[0] == self.loss_type:
                return choice[2]  # 返回详细信息字典
        return None

    @property
    def loss_icon(self):
        info = self.get_loss_type_info()
        return info['icon'] if info else '❓'

    @property
    def loss_color(self):
        info = self.get_loss_type_info()
        return info['color'] if info else '#000000'